<?php

/**
 * 基于thinkphp5框架单表操作的代码生成器
 *
 */
namespace app\gii\Controller;
set_time_limit(0);

use app\admin\model\Privilege;
use app\common\controller\BaseController;

use app\common\utils\JsonService;
use think\App;
use think\facade\Config;
use think\facade\Db;
use think\facade\Request;

//代码生成器所在文件夹路径
define('ROOT_PATH',str_replace('\\','/',root_path()));
define('APP_PATH',str_replace('\\','/',base_path()));
define('GII_PATH',APP_PATH.'gii/');
//代码生成器的模板代码所在路径
define('GII_TEMPLATE_PATH',GII_PATH.'templates/');
//代码生成器生成配置文件所在路径
define('GII_CONFIG_PATH',GII_PATH.'table_configs/');
define('GII_PRIVILEGE_PATH',GII_PATH.'privilege_tmp/');
class Index extends BaseController
{
    public function __construct(App $app)
    {
        parent::__construct($app);
        $token = app()->config->get('app.gii.token');
        if(session('gii_token') !=$token){
            $this->redirect(url('gii/login/index')->suffix(false)->build());
        }

    }

    //生成模型
    public function model(){
        if($this->request->isAjax()){
            $post = $this->request->post();
            $tableName = $this->request->post('tableName');
            $namespace = trim($this->request->post('namespace'),'\\');
            $extendClass = trim($this->request->post('extendClass'),'\\');
            if(!$namespace){
                return JsonService::error("命名不能为空");
            }
            if(!$extendClass){
                return JsonService::error("继承基类不能为空");
            }

            if(!class_exists($extendClass)){
                return JsonService::error("继承基类不存在");
            }

            $first_dir = strchr($namespace,'\\',true);

            if(!is_dir(ROOT_PATH.$first_dir)){
                return JsonService::error("命名空间必须与现有目录关联");
            }
            //$namespace_dir = str_replace('\\','/',ltrim(strchr($namespace,'\\'),'\\'));

            $namespace_dir = trim(str_replace('\\','/',$namespace),'//');
            $namespace_dir = strtolower(ROOT_PATH.$namespace_dir);

            if(!is_dir($namespace_dir)){
                mkdir($namespace_dir,0777,true);
            }


            if($tableName){
                //查询输入的表是否存在
                $table_info = Db::query("show table status where Name = '$tableName'");
                if($table_info){
                    $table_info = $table_info[0];
                    //如果存在就查询出表中所有的字段
                    $table_fields = Db::query("show full fields from $tableName");

                    $pri_key = Db::query("SELECT column_name FROM INFORMATION_SCHEMA.`KEY_COLUMN_USAGE` WHERE table_name='$tableName' AND constraint_name='PRIMARY';");
                    $pri = $pri_key?$pri_key[0]['column_name']:'id';

                    $comment_fields = Db::query("SELECT DISTINCT(DATA_TYPE),COLUMN_NAME,COLUMN_COMMENT FROM information_schema.columns WHERE table_name='$tableName'");

                    $tpName = $this->dbNameToTpName($tableName);//转成大写格式
                    $oriTableName = $this->dbNameToTpName($tableName,false);//去除表前缀的格式

                    //开始生成模型
                    if(file_exists($namespace_dir.'/'.$tpName.'.php') && $post['is_continue'] == 0) {
                        return JsonService::error("模型文件已存在！",302,302);
                    }

                    include(GII_TEMPLATE_PATH.'config.php');
                    $str = ob_get_clean();
                    if(file_put_contents(GII_CONFIG_PATH.$tableName.'.php',"<?php \r\n ".$str."?>")){
                        //return JsonService::success('模型与数据表配置文件创建成功');
                        //$config = include(GII_CONFIG_PATH.$tableName.'.php');

                        ob_start();
                        include(GII_TEMPLATE_PATH.'baseModel.php');
                        $str = ob_get_clean();
                        if(file_put_contents($namespace_dir.'/'.$tpName.'.php',"<?php \r\n ".$str."?>")){
                            return JsonService::success('模型与数据表配置文件创建成功');
                        }
                    }


                }else{
                    return JsonService::error("输入的数据表不存在");
                }

            }else{
               return JsonService::error("请输入完整表名");
            }

        }

        return $this->fetch('create_model');
    }

    //生成CURD
    public function curd(){
        if($this->request->isAjax()) {
            $post = $this->request->post();
            $modelNameSpace = trim($post['modelName'],'\\');
            $namespace = trim($post['namespace'],'\\');
            $extendClass = trim($post['extendClass'],'\\');
            $action = $post['action_list'];

            $is_privilege = $post['is_privilege'];
            $parent_id = $this->request->post('parent_id',-1);

            if(!$modelNameSpace){
                return JsonService::error("使用模型不能为空");
            }
            if (!$namespace) {
                return JsonService::error("控制器命名空间不能为空");
            }
            if (!$extendClass) {
                return JsonService::error("控制器继承基类不能为空");
            }

            if(empty($action)){
                return JsonService::error("至少生成一个方法");
            }
            if (!class_exists($modelNameSpace)) {
                return JsonService::error("模型类不存在");
            }

            if (!class_exists($extendClass)) {
                return JsonService::error("继承基类不存在");
            }

            $namespace_dir = str_replace('\\','/',ltrim(strchr($namespace,'\\',false),'\\'));


            $controller_name =  basename($namespace_dir);
            if(!preg_match("/^[a-z\d]*$/i",$controller_name))
            {
                return JsonService::error('控制器名称只能包含字母与数字');
            }


            if (!preg_match("/(^[A-Z]+)/", $controller_name))
            {
                return JsonService::error('控制器名称首字母必须大写');
            }

            $namespace_dir = dirname($namespace_dir);

            //echo Config::get('route.controller_layer');
            $layer = trim(substr($namespace_dir,strripos($namespace_dir,'/')),'/');

            $l = strpos($namespace_dir,'/');

            $module = substr($namespace_dir,0,$l);

            $app = trim(strchr($namespace,$module,true),'\\');

            if(!is_dir(ROOT_PATH.$app)){
               return JsonService::error('控制器命名空间必须与现有目录关联');
            }
            $module_dir = APP_PATH.substr($namespace_dir,0,$l);

            $controller_dir = APP_PATH.$namespace_dir;
            //namespace$controller_dir = ROOT_PATH.$app.'/'.$namespace_dir;

            if(!is_dir($controller_dir)){
                //mkdir($controller_dir,0777,true);
                return JsonService::error('控制器命名空间目录无效');
            }
            $module_dir = ROOT_PATH.$app.'/'.$module;

            //定义数据处理事件类
            $event_dir = ROOT_PATH.$app.'/'.$module.'/event';

            if(!is_dir($event_dir)){
                mkdir($event_dir,0777,true);
                //JsonService::error('控制器目录不存在');
            }

            //定义验证器目录
            $validate_dir = $module_dir.'/validate';
            //验证器命名空间
            $validateNamespace = $app.'\\'.$module.'\\validate';

            if(!is_dir($validate_dir)){
                mkdir($validate_dir,0777,true);
                //JsonService::error('控制器目录不存在');
            }


            $modelName = $this->toUnderScore(basename($modelNameSpace));
            $prefix = Db::table($modelName)->getConfig('prefix');
            $table = $prefix.$modelName;

            $table_info = Db::query("show table status where Name = '$table'");
            if(!$table_info){
                return JsonService::error("数据表不存在");
            }

            $table_info = $table_info[0];
            $tableName = $table;
            //如果存在就查询出表中所有的字段
            $table_fields = Db::query("show full fields from $tableName");
            $tpName = $this->dbNameToTpName($tableName);//转成大写格式
            $oriTableName = $this->dbNameToTpName($tableName,false);//去除表前缀的格式
            $event_name = $tpName.'Event';

            //定义视图目录
            $view_dir = $module_dir.'/view/'. $oriTableName;

            //是否存在多层级控制器
            if(strpos(','.'controller'.',',','.$layer.',') ===false){
                $view_dir = $module_dir.'/view/'.$layer.'/'. $oriTableName;
            }

            if(!is_dir($view_dir)){
                mkdir($view_dir,0777,true);
            }

            //include(GII_TEMPLATE_PATH.'config.php');
            if(!file_exists(GII_CONFIG_PATH.$tableName.'.php')) {
                ob_start();
                include(GII_TEMPLATE_PATH.'config.php');
                $str = ob_get_clean();
                file_put_contents(GII_CONFIG_PATH . $tableName . '.php', "<?php \r\n " . $str . "?>");
                    //return JsonService::success('模型配置文件创建成功');

                    //$config = include(GII_CONFIG_PATH.$tableName.'.php');

                    //ob_start();
                    //include(GII_TEMPLATE_PATH.'baseModel.php');
                    /*
                    $str = ob_get_clean();
                    if(file_put_contents($namespace_dir.'/'.$tpName.'.php',"<?php \r\n ".$str."?>")){
                        return JsonService::success('模型与数据表配置文件创建成功');
                    }
                    */
            }

            //判断控制器是否存在
            if(file_exists($controller_dir.'/'.$controller_name.'.php') && $post['is_continue'] == 0){
                return JsonService::error("控制器已经存在！",302,302);
            }

            //载入配置
            $config = include(GII_CONFIG_PATH.$tableName.'.php');
            //生成数据验证文件
            ob_start();
            include(GII_TEMPLATE_PATH.'validate.php');
            $str = ob_get_clean();
            file_put_contents($validate_dir.'/'.basename($modelNameSpace).'Validate.php',"<?php \r\n".$str);

            //生成控制器
            ob_start();
            include(GII_TEMPLATE_PATH.'controller.php');
            $str = ob_get_clean();
            file_put_contents($controller_dir.'/'.$controller_name.'.php',"<?php \r\n".$str);

            //生成控制器处理类
            ob_start();
            include(GII_TEMPLATE_PATH.'event.php');
            $str = ob_get_clean();
            file_put_contents($event_dir.'/'.basename($modelNameSpace).'Event.php',"<?php \r\n".$str);

            /******************生成相应的add,edit,del模板*******************/
            //生成新增模板
            if(in_array('create',$action)) {
                ob_start();
                include(GII_TEMPLATE_PATH . 'create.html');
                $str = ob_get_clean();
                file_put_contents($view_dir . '/create.html', $str);
            }

            //生成修改模板
            if(in_array('update',$action)) {
                ob_start();
                include(GII_TEMPLATE_PATH.'update.html');
                $str = ob_get_clean();
                file_put_contents($view_dir.'/update.html',$str);
            }

            //生成列表模板
            if(in_array('index',$action)) {
                ob_start();
                include(GII_TEMPLATE_PATH . 'index.html');
                $str = ob_get_clean();
                file_put_contents($view_dir . '/index.html', $str);
            }

            //生成详情模板
            if(in_array('view',$action)) {
                ob_start();
                include(GII_TEMPLATE_PATH . 'view.html');
                $str = ob_get_clean();
                file_put_contents($view_dir.'/view.html',$str);
            }

            if($is_privilege == 1){
                if($parent_id >-1){
                    $file = $tableName.'_tmp.tmp';
                    if(!is_dir(GII_PRIVILEGE_PATH)){
                        mkdir(GII_PRIVILEGE_PATH,0777,true);
                    }
                    if(!file_exists(GII_PRIVILEGE_PATH.$file)){
                        $pri_order = Db::name('privilege')->max('pri_order');

                        $tableComment = str_replace('表','',$table_info['Comment']);

                        //生成列表权限
                        $insert = [
                            'pri_name'=> $tableComment.'列表',
                            'module_name'=>$module,
                            'controller_name'=>$controller_name,
                            'action_name'=>'index',
                            'pri_order'=>$pri_order+1,
                            'is_menu' =>1,
                            'parent_id'=>$parent_id
                        ];

                        $list_id = Db::name('privilege')->insertGetId($insert);
                        //生成新增权限
                        $insert = [
                            'pri_name'=> '新增'.$tableComment,
                            'module_name'=>$module,
                            'controller_name'=>$controller_name,
                            'action_name'=>'create',
                            'is_menu' =>0,
                            'parent_id'=>$list_id
                        ];
                        Db::name('privilege')->insertGetId($insert);

                        //生成编辑权限
                        $insert = [
                            'pri_name'=> '编辑'.$tableComment,
                            'module_name'=>$module,
                            'controller_name'=>$controller_name,
                            'action_name'=>'update',
                            'is_menu' =>0,
                            'parent_id'=>$list_id
                        ];
                        Db::name('privilege')->insertGetId($insert);

                        //生成删除权限
                        $insert = [
                            'pri_name'=> '删除'.$tableComment,
                            'module_name'=>$module,
                            'controller_name'=>$controller_name,
                            'action_name'=>'delete',
                            'is_menu' =>0,
                            'parent_id'=>$list_id
                        ];
                        Db::name('privilege')->insertGetId($insert);
                        touch(GII_PRIVILEGE_PATH.$file);
                    }
                }
            }

            return JsonService::success('创建成功');

        }

        $privilegeData = Privilege::getTree();


        return $this->fetch('create_curd',['privilegeData'=>$privilegeData]);
    }

    //把表名转成tp框架规则的名称
    public function dbNameToTpName($tableName,$uc=true)
    {
        $tpName = explode('_', $tableName);
        unset($tpName[0]);
        if ($uc) {
            //把数组的每个元素都作用到ucfist函数上
            $tableName = array_map('ucfirst', $tpName);
            return implode($tableName);
        }else{
            return implode('_',$tpName);
        }
    }

    //去除表前缀
    public function dbNameToSuffix($tableName){
        $tpName = explode('_',$tableName);
        unset($tpName[0]);
        return implode('_',$tpName);
    }

    //获取配置文件
    public function getConfig($tableName){
        //载入配置文件
        $config = include(GII_CONFIG_PATH.$tableName);
        return $config;
    }

    //驼峰命名转下划线命名
    function toUnderScore($str)
    {
        $dstr = preg_replace_callback('/([A-Z]+)/',function($matchs)
        {
            return '_'.strtolower($matchs[0]);
        },$str);
        return trim(preg_replace('/_{2,}/','_',$dstr),'_');
    }
}













